package com.cimstech.resources;

import java.io.*;
import java.util.*;
import java.util.logging.Logger;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;

import com.cimstech.connect.*;
import com.cimstech.model.*;
import json.JSONArray;
import json.JSONException;
import json.JSONObject;
import monfox.stack.iec61850.api.*;
import monfox.stack.iec61850.api.client.*;
import monfox.stack.iec61850.api.file.FileService;
import monfox.stack.iec61850.api.file.VFS;
import monfox.stack.osi.session.EX_SPDU;
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;

/**
 * Jersey 提供的RESTful接口类
 */
@Path(value = "/")
public class IECResources {
    private static int filedirTimeOut = 10000;
    private static HashMap<String, IEC61850Client> connPool = new HashMap<String, IEC61850Client>();
    private static final String ENABLE = "Enable";
    private static final String DISABLE = "Disable";
    private static Map<String, Node> nodes = new HashMap<String, Node>();
    private static Map<String, FileService> fileService = new HashMap<String, FileService>();

    public IECResources() {
        System.out.println("资源服务实例化");
        String relativelyPath = System.getProperty("user.dir");
        System.out.println(relativelyPath);
    }

    /**
     * 连接设备(不获取全模型)
     *
     * @param url 设备IP
     * @return 是否连接成功(用于返回报错信息)
     */
    @Path(value = "/Connect")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public IECResult Connect(@FormParam("url") String url) {
        Logger logger = Logger.getLogger("Connect");
        logger.info("收到数据：url: " + url);
        IECResult result = new IECResult();
        try {
            Connect.connect(url, connPool);
            result.setIp(url);
            result.setIecResponseMessage(IECResult.SUCCESS);
        } catch (ACSIServiceErrorException e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.ACSI_ERROR + e.getServiceError());
            e.printStackTrace();
        } catch (ModelCommunicationException e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.MODELCOMMUNICATION_ERROR);
            e.printStackTrace();
        } catch (ModelValueException e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.MODELVALUE_ERROR);
            e.printStackTrace();
        } catch (ModelTimeoutException e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.TIMEOUT_ERROR);
            e.printStackTrace();
        } catch (ModelServiceException e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.MODELSERVICE_ERROR);
            e.printStackTrace();
        } catch (ModelException e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.MODEL_ERROR);
            e.printStackTrace();
        } catch (Exception e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.SYSTEM_ERROR);
            e.printStackTrace();
        }
        logger.info("返回数据 " + result.getIecResponseMessage());
        return result;
    }

    /**
     * 获取全模型
     *
     * @param url     设备IP
     * @param pattern 获取的方式(获取/重新载入)
     * @param id      当前节点ID
     * @return 子节点
     */
    @Path(value = "/Model/{pattern}")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String getModel(@FormParam("url") String url, @PathParam("pattern") String pattern, @FormParam("id") String id) {
        Logger logger = Logger.getLogger("getModel");
        logger.info("收到数据：url: " + url + " pattern: " + pattern + " id: " + id);
        List<Node> list = new ArrayList<Node>();
        int j = 100;
        try {
            Connect.connect(url, connPool);
            IEC61850Client client = connPool.get(url);

            if (id == null) {
                Node node = new Node(false, client.getIED().getName(), client.getIED().getName(), "IED");
                nodes.put(node.getId(), node);
                list.add(node);
            } else if (nodes.get(id) == null) {
            } else {
                Node node = nodes.get(id);
                if ("IED".equals(node.getType())) {
                    for (LD ld : client.getLDs()) {
                        Node n = new Node(false, ld.getName(), ld.getName(), "LD");
                        list.add(n);
                        nodes.put(n.getId(), n);
                    }
                } else if ("LD".equals(node.getType())) {
                    String ldId = node.getId();
                    LD ld = client.getLD(ldId);
                    for (LN ln : ld.getLNs()) {
                        Node n = new Node(false, ln.getName(), node.getId() + "/" + ln.getObjectRef(), "LN");
                        list.add(n);
                        nodes.put(n.getId(), n);
                    }
                } else if ("LN".equals(node.getType())) {
                    String[] ss = node.getId().split("/");
                    LN ln = client.getLD(ss[0]).getLN(ss[1]);
                    for (FC fc : ln.getFCs()) {
                        Node n = new Node(false, fc.getName(), node.getId() + "$" + fc.getName(), "FC");
                        list.add(n);
                        nodes.put(n.getId(), n);
                    }
                    for (DataSet ds : ln.getDataSets()) {
                        Node n = new Node(true, ds.getName(), node.getId() + "$" + ds.getName(), "DS");
                        list.add(n);
                        nodes.put(n.getId(), n);
                    }
                    for (Log lg : ln.getLogs()) {
                        Node n = new Node(true, lg.getName(), node.getId() + "$" + lg.getName(), "LG");
                        list.add(n);
                        nodes.put(n.getId(), n);
                    }
                } else if ("FC".equals(node.getType())) {
                    String[] ss = node.getId().split("/");
                    FC fc = (FC) client.getLD(ss[0]).getChildForPath(ss[1]);
                    for (DO oo : fc.getDOs()) {
                        Node n = new Node(false, oo.getName(), node.getId() + "$" + oo.getName(), "DO");
                        list.add(n);
                        nodes.put(n.getId(), n);
                    }
                } else if ("DO".equals(node.getType())) {
                    String[] ss = node.getId().split("/");
                    DO oo = (DO) client.getLD(ss[0]).getChildForPath(ss[1]);
                    for (DA da : oo.getDAs()) {
                        Node n = new Node(da.getDACount() == 0, da.getName(), node.getId() + "$" + da.getName(), "DA");
                        list.add(n);
                        nodes.put(n.getId(), n);
                    }
                } else if ("DA".equals(node.getType())) {
                    String[] ss = node.getId().split("/");
                    DA a = (DA) client.getLD(ss[0]).getChildForPath(ss[1]);
                    for (DA da : a.getDAs()) {
                        Node n = new Node(da.getDACount() == 0, da.getName(), node.getId() + "$" + da.getName(), "DA");
                        list.add(n);
                        nodes.put(n.getId(), n);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        String resp = (new JSONArray(list, false)).toString();
        logger.info("返回数据：" + resp);
        int m = 100;
        return resp;
    }

    /**
     * 读取数据
     *
     * @param url 设备地址
     * @param id  量测ID
     * @return 数据组
     */
    @Path(value = "/Value")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public IECResult getValue(@FormParam("url") String url, @FormParam("id") String id) {
        Logger logger = Logger.getLogger("getValue");
        logger.info("收到数据：url: " + url + " id: " + id);
        IECResult result = new Values();
        try {
            Connect.connect(url, connPool);
            Execute.execute(Commands.READ, id, connPool.get(url), result);
            result.setIp(url);
            result.setIecResponseMessage(IECResult.SUCCESS);
        } catch (ModelValueException e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.MODELVALUE_ERROR);
            e.printStackTrace();
        } catch (ModelTimeoutException e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.TIMEOUT_ERROR);
            e.printStackTrace();
        } catch (ModelServiceException e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.MODELSERVICE_ERROR);
            e.printStackTrace();
        } catch (ACSIServiceErrorException e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.ACSI_ERROR + e.getServiceError());
            e.printStackTrace();
        } catch (SCADAException e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.SCADA_ERROR + e.getMessage());
            e.printStackTrace();
        } catch (ModelException e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.MODEL_ERROR);
            e.printStackTrace();
        } catch (Exception e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.SYSTEM_ERROR);
            e.printStackTrace();
        }
        logger.info("返回数据 " + result.toString());
        return result;
    }

    /**
     * 报告开关
     *
     * @param url     设备地址
     * @param _switch 开关状态
     * @return 是否开启成功
     */
    @Path(value = "/Report")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public IECResult report(@FormParam("url") String url, @FormParam("_switch") String _switch) {
        Logger logger = Logger.getLogger("report");
        logger.info("收到数据：url: " + url + " _switch: " + _switch);
        IECResult result = new IECResult();
        try {
            Connect.connect(url, connPool);
            if (ENABLE.equals(_switch)) {
                Execute.execute(Commands.ENABLE_BRCB, null, connPool.get(url), result);
                Execute.execute(Commands.ENABLE_URCB, null, connPool.get(url), result);
            } else if (DISABLE.equals(_switch)) {
                Execute.execute(Commands.DISABLE_BRCB, null, connPool.get(url), result);
                Execute.execute(Commands.DISABLE_URCB, null, connPool.get(url), result);
            }
            result.setIecResponseMessage(IECResult.SUCCESS);
            result.setIp(url);
        } catch (ModelValueException e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.MODELVALUE_ERROR);
            e.printStackTrace();
        } catch (ModelTimeoutException e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.TIMEOUT_ERROR);
            e.printStackTrace();
        } catch (ModelServiceException e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.MODELSERVICE_ERROR);
            e.printStackTrace();
        } catch (ACSIServiceErrorException e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.ACSI_ERROR + e.getServiceError());
            e.printStackTrace();
        } catch (SCADAException e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.SCADA_ERROR + e.getMessage());
            e.printStackTrace();
        } catch (ModelException e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.MODEL_ERROR);
            e.printStackTrace();
        } catch (Exception e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.SYSTEM_ERROR);
            e.printStackTrace();
        }
        logger.info("返回数据 " + result.getIecResponseMessage());
        return result;
    }

    /**
     * 客戶端打開時載入服務器中的鏈接
     *
     * @return 服務器中已經加載的連接
     */
    @Path(value = "/getConnList")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public ConnList getConnList() {

        Logger logger = Logger.getLogger("getConnList");
        logger.info("收到数据  /getConnList");

        ConnList connList = new ConnList();
        connList.setConnList(new ArrayList<ConnectInfo>());
        try {
            Iterator<String> list = connPool.keySet().iterator();
            while (list.hasNext()) {
                String ip = list.next();
                String isConnect = connPool.get(ip).isConnected() ? "connected" : "disconnect";
                connList.getConnList().add(new ConnectInfo(ip, isConnect));
            }
            connList.setIecResponseMessage(IECResult.SUCCESS);
        } catch (Exception e) {
            connList.setIecResponseMessage(IECResult.ERROR);
            connList.setIecResponseCause(ErrorMessage.SYSTEM_ERROR);
            e.printStackTrace();
        }
        logger.info("返回数据 " + connList.getConnList());
        return connList;
    }

    /**
     * 删除链接，用于相应客户端删除某连接的接口
     *
     * @param url 设备地址
     * @return 删除成功
     */
    @Path(value = "/Connect/{url}")
    @DELETE
    @Produces(MediaType.APPLICATION_JSON)
    public IECResult removeConn(@PathParam("url") String url) {
        Logger logger = Logger.getLogger("removeConn");
        logger.info("收到数据 url: " + url);
        IECResult result = new IECResult();
        try {
            if (connPool.containsKey(url)) {
                if (connPool.get(url).isConnected()) {
                    connPool.get(url).performRelease();
                }
                connPool.remove(url);
            }
            result.setIp(url);
            result.setIecResponseMessage(IECResult.SUCCESS);
        } catch (ModelCommunicationException e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.MODELCOMMUNICATION_ERROR);
            e.printStackTrace();
        } catch (Exception e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.SYSTEM_ERROR);
            e.printStackTrace();
        }
        logger.info("返回数据 " + result.getIecResponseMessage());
        return result;
    }

    /**
     * 断开连接(不删除)
     *
     * @param url 设备地址
     * @return 断开状态
     */
    @Path(value = "/tearingConn")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public IECResult tearingConn(@FormParam("url") String url) {
        Logger logger = Logger.getLogger("tearingConn");
        logger.info("收到数据 url: " + url);
        IECResult result = new IECResult();
        try {
            if (connPool.containsKey(url) && connPool.get(url).isConnected()) {
                connPool.get(url).performRelease();
            }
            result.setIecResponseMessage(IECResult.SUCCESS);
        } catch (ModelCommunicationException e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.MODELCOMMUNICATION_ERROR);
            e.printStackTrace();
        } catch (Exception e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.SYSTEM_ERROR);
            e.printStackTrace();
        }
        logger.info("返回数据 " + result.getIecResponseMessage());
        return result;
    }

    @Path(value = "/getFileDir")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public FileDirectories getFileDir(@QueryParam("url") String url, @QueryParam("id") String path) {
        Logger logger = Logger.getLogger("getFileDir");
        logger.info("收到数据 url: " + url);
        List<FileDirectory> list;
        FileDirectories result = new FileDirectories();
        try {
            Connect.connect(url, connPool);
            IEC61850Client client = connPool.get(url);
            list = new ArrayList<FileDirectory>();
            if (!fileService.containsKey(url)) {
                FileService file_service = client.getFileService();
                file_service.setTimeoutMillis(filedirTimeOut);
                fileService.put(url, file_service);
            }
            if (path == null) {
                path = "/";
            }
            path = path.replace("\\", "/");
            List<FileService.DirEntry> dir_entry_list = fileService.get(url).performGetDirectory(path);
            for (FileService.DirEntry entry : dir_entry_list) {
                FileDirectory record = new FileDirectory(entry.isDirectory(), entry.getName(), entry.getPath(), entry.getParent(), entry.getSize(), entry.getLastModifiedTime());
                list.add(record);
            }
            result.setNodes(list);
            result.setIecResponseMessage(IECResult.SUCCESS);
        } catch (ModelValueException e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.MODELVALUE_ERROR);
            e.printStackTrace();
        } catch (ACSIServiceErrorException e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.ACSI_ERROR + e.getServiceError().toString());
            e.printStackTrace();
        } catch (ModelTimeoutException e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.TIMEOUT_ERROR);
            e.printStackTrace();
        } catch (ModelCommunicationException e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.MODELCOMMUNICATION_ERROR);
            e.printStackTrace();
        } catch (ModelException e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.MODEL_ERROR);
            e.printStackTrace();
        } catch (Exception e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.SYSTEM_ERROR);
            e.printStackTrace();
        }
        logger.info("返回数据" + result);
        return result;
    }

    @Path(value = "/setting")
    @POST
    @Produces()
    public void settings(@FormParam("connectTimeOut") int connectTimeOut, @FormParam("filedirTimeOut") int filedirTimeOut) {
        this.filedirTimeOut = filedirTimeOut * 1000;
    }

    @GET
    @Path("/getFile/{fileName}")
    @Produces(MediaType.APPLICATION_OCTET_STREAM)//返回方式为流
    public byte[] getFile(@QueryParam("url") String url, @QueryParam("id") String path) {
        Logger logger = Logger.getLogger("getFile");
        logger.info("收到数据 url: " + url);
        try {
            Connect.connect(url, connPool);
            IEC61850Client client = connPool.get(url);
            if (!fileService.containsKey(url)) {
                FileService file_service = client.getFileService();
                file_service.setTimeoutMillis(filedirTimeOut);
                fileService.put(url, file_service);
            }
            if (path == null) {
                path = "/";
            }
            path = path.replace("\\", "/");
            byte[] file_contents = fileService.get(url).performGetFile(path);
            return file_contents;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    @Path("/upload")
    @POST
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    @Produces(MediaType.APPLICATION_JSON)
    public IECResult writeFile(@FormDataParam("url") String url, @FormDataParam("path") String path, @FormDataParam("file") InputStream fileInputStream,
                               @FormDataParam("file") FormDataContentDisposition disposition) {
        Logger logger = Logger.getLogger("writeFile");
        logger.info("收到数据 url: " + url + "path: " + path + "file: " + disposition.getFileName());
        IECResult result = new IECResult();
        try {
            Connect.connect(url, connPool);
            IEC61850Client client = connPool.get(url);
            if (!fileService.containsKey(url)) {
                FileService file_service = client.getFileService();
                file_service.setTimeoutMillis(filedirTimeOut);
                fileService.put(url, file_service);
            }
            File file = new File("\\" + url + path);
            if (!file.exists() && !file.isDirectory()) {
                file.mkdirs();
            } else {
            }
            fileService.get(url).setVFS("\\" + url + path);
            VFS.VFile vFile = fileService.get(url).getVFS().createFile(disposition.getFileName());
            ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
            byte[] buff = new byte[100];
            int rc = 0;
            while ((rc = fileInputStream.read(buff, 0, 100)) > 0) {
                swapStream.write(buff, 0, rc);
            }
            byte[] in2b = swapStream.toByteArray();
            vFile.append(in2b);
            if (path == null) {
                path = "/";
            }
            path = path.replace("\\", "/");
            fileService.get(url).performSetFile(vFile, path + disposition.getFileName());
            vFile.delete();
            fileInputStream.close();
            result.setIecResponseMessage(IECResult.SUCCESS);
        } catch (ModelValueException e) {
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.MODELVALUE_ERROR);
            e.printStackTrace();
        } catch (ACSIServiceErrorException e) {
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.ACSI_ERROR + e.getServiceError().toString());
            e.printStackTrace();
        } catch (ModelTimeoutException e) {
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.TIMEOUT_ERROR);
            e.printStackTrace();
        } catch (ModelCommunicationException e) {
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.MODELCOMMUNICATION_ERROR);
            e.printStackTrace();
        } catch (ModelException e) {
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.MODEL_ERROR);
            e.printStackTrace();
        } catch (Exception e) {
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.SYSTEM_ERROR);
            e.printStackTrace();
        }
        return result;
    }

    @Path("/DeleteFile")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public IECResult deleteFile(@FormParam("url") String url, @FormParam("items") String items) {
        IECResult result = new IECResult();
        ;
        try {
            Connect.connect(url, connPool);
            IEC61850Client client = connPool.get(url);
            if (!fileService.containsKey(url)) {
                FileService file_service = client.getFileService();
                file_service.setTimeoutMillis(filedirTimeOut);
                fileService.put(url, file_service);
            }
            JSONArray jsonArray = new JSONArray(items);
            int i = 0, j = 0;
            for (i = 0; i < jsonArray.length(); i++) {
                JSONObject item = jsonArray.getJSONObject(i);
                try {
                    fileService.get(url).performDeleteFile(item.getString("id"));
                } catch (Exception e) {
                    j++;
                }
            }
            result.setIecResponseMessage(IECResult.SUCCESS);
        } catch (ACSIServiceErrorException e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.ACSI_ERROR + e.getServiceError().toString());
            e.printStackTrace();
        } catch (ModelException e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.MODEL_ERROR);
            e.printStackTrace();
        } catch (Exception e) {
            result.setIp(url);
            result.setIecResponseMessage(IECResult.ERROR);
            result.setIecResponseCause(ErrorMessage.SYSTEM_ERROR);
            e.printStackTrace();
        }
        return result;
    }

    public static Map getConnPool() {
        return connPool;
    }
}